﻿// INGENIOUS FRAMEWORK - Semantic Web Development Simplified
// Copyright (C) 2012 Linked Data Tools

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using Ingenious.Graph;

namespace Ingenious.Owl.Linq
{
    public abstract class RdfParserBase : IDisposable
    {
        private readonly IList<Triple> m_triples = new List<Triple>();

        private readonly string m_fileName;
        private readonly Uri m_webAddress;

        private static readonly Dictionary<string, HashSet<string>> s_validQualifiedNames =
            new Dictionary<string, HashSet<string>>()
            {
                // RDF namespace
                {
                    RdfHelper.RdfXmlNamespace,
                    new HashSet<string>()
                    {
                        // Rdf qualified names
                        RdfHelper.RdfLocalName,
                        RdfHelper.DescriptionLocalName,
                        RdfHelper.PropertyLocalName,
                        RdfHelper.TypeLocalName,
                    } 
                },
                // RDFS namespace
                {
                    RdfsHelper.RdfsXmlNamespace,
                    new HashSet<string>()
                    {
                        // Rdfs qualified names
                        RdfsHelper.ClassLocalName,
                        RdfsHelper.CommentLocalName,
                        RdfsHelper.DomainLocalName,
                        RdfsHelper.LabelLocalName,
                        RdfsHelper.RangeLocalName,
                        RdfsHelper.SubPropertyOfLocalName,
                    }
                },
                // OWL namespace
                {
                    OwlHelper.OwlXmlNamespace,
                    new HashSet<string>()
                    {
                        // Owl qualified names
                        OwlHelper.ClassLocalName,
                    }
                },
            };

        #region Object Lifetime
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="fileName">The RDF file to parse</param>
        public RdfParserBase(string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }

            m_fileName = fileName;

            // Retrieve the RDF content from the target
            ParseContent(GetContent());
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="target">The RDF file to parse (URI for web based resource)</param>
        public RdfParserBase(Uri webAddress)
        {
            if (webAddress == null)
            {
                throw new ArgumentNullException("webAddress");
            }

            m_webAddress = webAddress;

            // Retrieve the RDF content from the target
            ParseContent(GetContent());
        }

        public virtual void Dispose()
        {
            m_triples.Clear();
        }
        #endregion

        private string GetFileContent()
        {
            string rdfContent = null;

            try
            {
                using (StreamReader streamReader = new StreamReader(m_fileName))
                {
                    rdfContent = streamReader.ReadToEnd();
                }
            }
            catch (ArgumentException)
            {
                throw new ParseException("Invalid filename '" + m_fileName + "'");
            }
            catch (FileNotFoundException)
            {
                throw new ParseException("File not found '" + m_fileName + "'");
            }
            catch (DirectoryNotFoundException)
            {
                throw new ParseException("Path not found '" + m_fileName + "'");
            }
            catch (IOException ex)
            {
                throw new ParseException("I/O error ('" + ex.Message + "')", ex);
            }

            return rdfContent;
        }

        protected string GetContent()
        {
            string rdfContent = null;

            if (m_fileName != null)
            {
                rdfContent = GetFileContent();
            }
            else if (m_webAddress != null)
            {
                throw new NotImplementedException();
            }

            // Validate the content is in the format specified
            ValidateContent(rdfContent);

            return rdfContent;
        }

        protected abstract void ValidateContent(string rdfContent);
        protected abstract void ParseContent(string rdfContent);

        #region Properties
        public IList<Triple> Triples
        {
            get { return m_triples; }
        }

        protected static Dictionary<string, HashSet<string>> ValidQualifiedNames
        {
            get { return s_validQualifiedNames; }
        }
        #endregion
    }
}